/****************************************************************************
 * Copyright (C) 2009-2010 SciTouch LLC
 * 
 * This file is part of Indigo toolkit.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/ 

//
// This is a command line utility for producing canonical SMILES
// or layered code for molecules in MOL or SDF format
//

#include "base_cpp/array.h"
#include "base_cpp/output.h"
#include "base_cpp/scanner.h"

#include "molecule/sdf_loader.h"

#include "cano.h"

void usage ()
{
   printf(
      "Usage:\n"
      "  cano-utility filename.{mol,smi,sdf,sdf.gz} [parameters]\n"
      "  cano-utility - SMILES [parameters]\n"
      "Parameters:\n"
      "  -smiles          Output canonical SMILES (default)\n"
      "  -layered         Output canonical layered code\n"
      "  -id <string>     ID field in SDF file\n"
      "  -no-arom         Do not aromatize molecules\n"
      "  -no-tetrahedral  Ignore tetrahedral stereocenters\n"
      "  -no-cistrans     Ignore cis-trans bonds information\n"
      "Examples:\n"
      "   cano-utility infile.sdf\n"
      "   cano-utility infile.sdf.gz -id molregno > results.txt\n"
      "   cano-utility infile.smi -layered -no-cistrans\n"
      "   cano-utility - 'NC1C=CC(O)=CC=1'\n"
      );
}

void processMolecule (const char *molecule, bool smiles, Output &output)
{
   const char *result;
   
   if (!canoSetMolecule(molecule))
   {
      output.printf("error: %s\n", canoGetLastError());
      return;
   }

   int res;

   if (smiles)
      res = canoGetCanonicalSmiles(&result);
   else
      res = canoGetLayeredCode(&result);

   if (!res)
   {
      output.printf("error: %s\n", canoGetLastError());
      return;
   }

   output.printf("%s\n", result);
}

int main (int arg_c, char *arg_v[])
{
   if (arg_c < 2)
   {
      usage();
      return -1;
   }

   StandardOutput output;
   bool smiles = true;
   bool no_cistrans = false;
   bool no_tetrahedral = false;
   bool no_arom = false;
   int arg_pos = 2;
   const char *idfield = 0;
   const char *filename = 0;

   if (strcmp(arg_v[1], "-") == 0)
      arg_pos = 3;
   else
      filename = arg_v[1];

   while (arg_pos < arg_c)
   {
      if (strcmp(arg_v[arg_pos], "-smiles") == 0)
         smiles = true;
      else if (strcmp(arg_v[arg_pos], "-layered") == 0)
         smiles = false;
      else if (strcmp(arg_v[arg_pos], "-no-cistrans") == 0)
         no_cistrans = true;
      else if (strcmp(arg_v[arg_pos], "-no-arom") == 0)
         no_arom = true;
      else if (strcmp(arg_v[arg_pos], "-no-tetrahedral") == 0)
         no_tetrahedral = true;
      else if (strcmp(arg_v[arg_pos], "-id") == 0)
      {
         if (++arg_pos >= arg_c)
         {
            usage();
            return 0;
         }

         idfield = arg_v[arg_pos];
      }
      else
      {
         usage();
         return -1;
      }
      arg_pos++;
   }

   {
      char options[1024] = {0};

      if (no_arom)
         strcat(options, "-AROMATICITY ");
      if (no_cistrans)
         strcat(options, "-CISTRANS ");
      if (no_tetrahedral)
         strcat(options, "-TETRAHEDRAL ");

      if (options[0] != 0)
         if (!canoSetOptions(options))
         {
            fprintf(stderr, "%s\n", canoGetLastError());
            return -2;
         }
   }

   if (filename == 0)
   {
      processMolecule(arg_v[2], smiles, output);
      return 0;
   }

   try
   {
      Array<char> buf;

      if (strlen(filename) > 4 && strcmp(filename + strlen(filename) - 4, ".mol") == 0)
      {
         FileScanner scanner(filename);

         scanner.readAll(buf);
         buf.push(0);
         processMolecule(buf.ptr(), smiles, output);
      }
      else if (strlen(filename) > 4 && strcmp(filename + strlen(filename) - 4, ".smi") == 0)
      {
         FileScanner scanner(filename);

         while (!scanner.isEOF())
         {
            scanner.readString(buf, true);
            processMolecule(buf.ptr(), smiles, output);
         }
      }
      else if ((strlen(filename) > 4 && strcmp(filename + strlen(filename) - 4, ".sdf") == 0) ||
               (strlen(filename) > 7 && strcmp(filename + strlen(filename) - 7, ".sdf.gz") == 0))
      {
         FileScanner scanner(filename);
         SdfLoader sdf_loader(scanner);

         if (idfield != 0)
            sdf_loader.initProperties(idfield);

         while (!sdf_loader.isEOF())
         {
            sdf_loader.readNext();
            sdf_loader.data.push(0);

            if (idfield != 0 && sdf_loader.properties.at2(idfield) != 0)
            {
               const char *id = sdf_loader.properties.at(idfield).ptr();

               if (id != 0 && strlen(id) > 0)
               {
                  output.printf("%s ", id);
                  output.flush();
               }
            }

            processMolecule(sdf_loader.data.ptr(), smiles, output);
         }
      }
      else
      {
         usage();
         return -1;
      }
   }
   catch (Exception &ex)
   {
      fprintf(stderr, "error: %s\n", ex.message());
   }
}
